/* @flow */

import config from '../config'
import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { mark, measure } from '../util/perf'
import { initLifecycle, callHook } from './lifecycle'
import { initProvide, initInjections } from './inject'
import { extend, mergeOptions, formatComponentName } from '../util/index'

let uid = 0



export function initMixin(Vue: Class<Component>) {
  /**
 * 执行完initMixin方法后，Vue将拥有的属性为
 * 
 * Vue._uid = 0
 * Vue._isVUe = true
 * 
 * 经过mergeOptions后
 * Vue.$options = {
 *   el: '#app',
 *   data: function mergedInstanceDataFn(){ return {  message: 'hello world' }  }
 * }
 * 
 * 经过initLifecycle后
 * Vue._renderProxy = this
 * Vue._self = this
 * Vue.$parent = undefined
 * Vue.$root = this
 * Vue.$children = []
 * Vue.$refs = {}
 * Vue._watcher = null
 * Vue._inactive = null
 * Vue._directInactive = false
 * Vue._isMounted = false
 * Vue._isDestroyed = false
 * Vue._isBeingDestroyed = false
 * 
 * //经过initEvents后
 * Vue._events = {}
 * Vue._hasHookEvent = false
 * 
 * //经过initRender后
 * Vue._vnode = null
 * Vue._staticTrees = null
 * Vue.$vnode = undefined
 * Vue.$slots = {}
 * Vue.$scopedSlots = {} 冻结的对象
 * Vue._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
 * Vue.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
 * Vue.$attrs = {} //响应式劫持的属性
 * Vue.$listeners = {} ////响应式劫持的属性
 * 
 * //经过initState后
 * Vue._watchers = []
 * Vue._data = {  message: 'hello world' } 
 */
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++

    vm._isVue = true

    //Vue的构造器实例不存在_isComponent属性，只有自定义组件才会存在当前属性
    //_isComponent在vdom/create-component.js/createComponentInstanceForVnode方法里面设置
    if (options && options._isComponent) {
      // 初始化组件，为组件添加$options属性
      initInternalComponent(vm, options)
    } else {
      //合并属性策略
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      //开发环境下采用了proxy来代理了数据
      //代理后的数据在对象render函数解析的时候就可以访问了
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }

    vm._self = vm
    /**
     *  根据$options实现建立父子关系
     *  在父中push当前作为子集进去
     *  vm.$parent 
     *  vm.$root
     *  vm.$children
     *  vm.$refs
     *  vm._watcher
     *  vm._inactive
     *  vm._directInactive
     *  vm._isMounted
     *  vm._isDestroyed 
     *  vm._isBeingDestroyed 
     */
    initLifecycle(vm)
    //初始化$listence
    initEvents(vm)
    /**
     * 挂载_c和$createElement渲染方法，
     * 同时添加$attr和$listeners属性
     * 将默认不传值插槽属性{ 'defalut': fn }赋值到vm.$slot上
     */
    initRender(vm)
    //调用生命函数
    callHook(vm, 'beforeCreate')
    //初始化inject属性
    initInjections(vm) // resolve injections before data/props
    //初始化data属性，并且劫持属性
    initState(vm)
    //初始化Provide属性
    initProvide(vm) // resolve provide after data/props
    //调用声明函数
    callHook(vm, 'created')


    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}

export function initInternalComponent(vm: Component, options: InternalComponentOptions) {
  // 空对象
  const opts = vm.$options = Object.create(vm.constructor.options)
  // 得到组件的vnode对象
  const parentVnode = options._parentVnode
  // 当前组件的父级
  opts.parent = options.parent

  opts._parentVnode = parentVnode

  const vnodeComponentOptions = parentVnode.componentOptions
  opts.propsData = vnodeComponentOptions.propsData
  opts._parentListeners = vnodeComponentOptions.listeners
  opts._renderChildren = vnodeComponentOptions.children
  opts._componentTag = vnodeComponentOptions.tag

  if (options.render) {
    opts.render = options.render
    opts.staticRenderFns = options.staticRenderFns
  }
}


/**
 * 解析option属性，Vue.constructor.options = Vue.options
 * 这个options属性是在global-api/index.js/initGlobalAPI 方法挂载的
 * 属性的值为全局的组件，指令，过滤器，还有一个_base指向自身
 * {
 *  components: {KeepAlive: {…}, Transition: {…}, TransitionGroup: {…}}
    directives: {model: {…}, show: {…}}
    filters: {}
    _base: 当前自身
 * }
 */
export function resolveConstructorOptions(Ctor: Class<Component>) {
  let options = Ctor.options
  //只有是组件调用次方法才会走if分支，首次初始化不会走if
  if (Ctor.super) {
    //这里重复递归，直到获取到Vue构造器 { components， directives， filters， _base }
    const superOptions = resolveConstructorOptions(Ctor.super)
    const cachedSuperOptions = Ctor.superOptions

    //如果是一级component这里cachedSuperOptions === superOptions
    if (superOptions !== cachedSuperOptions) {
      // super option changed,
      // need to resolve new options.
      Ctor.superOptions = superOptions
      // check if there are any late-modified/attached options (#4976)
      const modifiedOptions = resolveModifiedOptions(Ctor)
      // update base extend options
      if (modifiedOptions) {
        extend(Ctor.extendOptions, modifiedOptions)
      }
      options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
      if (options.name) {
        options.components[options.name] = Ctor
      }
    }
  }
  return options
}

function resolveModifiedOptions(Ctor: Class<Component>): ?Object {
  let modified
  const latest = Ctor.options
  const sealed = Ctor.sealedOptions
  for (const key in latest) {
    if (latest[key] !== sealed[key]) {
      if (!modified) modified = {}
      modified[key] = latest[key]
    }
  }
  return modified
}
